use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize};
use std::fmt;

#[derive(Debug, Serialize, Deserialize)]
pub struct SiteInfo {
    #[serde(rename = "id")]
    pub site_id: i32,

    #[serde(rename = "host")]
    pub host: Option<String>,

    #[serde(rename = "lastcheckdate")]
    #[serde(with = "my_date_format")]
    pub last_check_time: NaiveDateTime,
}

impl fmt::Display for SiteInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "SiteId={}, Host={}, VideoUpdateMaxTime={}",
            self.site_id,
            self.host.as_deref().unwrap_or("None"),
            self.last_check_time.format("%Y-%m-%dT%H:%M:%S")
        )
    }
}
// 自定义日期格式序列化/反序列化
mod my_date_format {
    use chrono::NaiveDateTime;
    use serde::{self, Deserialize, Deserializer, Serializer};

    const FORMAT: &str = "%Y-%m-%dT%H:%M:%S";

    pub fn serialize<S>(date: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let s = date.format(FORMAT).to_string();
        serializer.serialize_str(&s)
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<NaiveDateTime, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        NaiveDateTime::parse_from_str(&s, FORMAT).map_err(serde::de::Error::custom)
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Book {
    #[serde(rename = "ssid")]
    pub site_id: i32,

    #[serde(rename = "url")]
    pub url: Option<String>,

    #[serde(rename = "uk")]
    pub uk: Option<String>,

    #[serde(rename = "name")]
    pub name: Option<String>,

    #[serde(rename = "finish")]
    pub finish: bool,

    #[serde(rename = "chapters")]
    pub chapters: Option<String>,

    #[serde(rename = "cover")]
    pub cover: Option<String>,
}

impl fmt::Display for Book {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "SiteId={}, Name={}, Url={}, Finish={}, Chapters={}, Cover={}",
            self.site_id,
            self.name.as_deref().unwrap_or("None"),
            self.url.as_deref().unwrap_or("None"),
            self.finish,
            self.chapters.as_deref().unwrap_or("None"),
            self.cover.as_deref().unwrap_or("None")
        )
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Chapter {
    #[serde(rename = "url")]
    pub url: Option<String>,

    #[serde(rename = "name")]
    pub name: Option<String>,

    #[serde(rename = "uk")]
    pub uk: Option<String>,

    #[serde(rename = "idx")]
    pub idx: i32,
}

impl fmt::Display for Chapter {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "Url={}, Name={}, Uk={}, Idx={}",
            self.url.as_deref().unwrap_or("None"),
            self.name.as_deref().unwrap_or("None"),
            self.uk.as_deref().unwrap_or("None"),
            self.idx
        )
    }
}

pub mod dto {
    use serde::{Deserialize, Serialize};
    use std::fmt;
    #[derive(Debug, Serialize, Deserialize)]
    pub struct TaskDTO {
        #[serde(rename = "url")]
        pub url: Option<String>,

        #[serde(skip_deserializing)]
        pub site_id: i32,

        #[serde(rename = "id")]
        pub chapter_id: i32,

        #[serde(rename = "bookid")]
        pub book_id: i32,
    }

    impl fmt::Display for TaskDTO {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            write!(
                f,
                "SiteId={},BookId={},  ChapterId={}，Url={}",
                self.site_id,
                self.chapter_id,
                self.book_id,
                self.url.as_deref().unwrap_or("None"),
            )
        }
    }
}
